package db

import (
	"fmt"
	"github.com/redis/go-redis/v9"
	"gorm.io/gorm/logger"
	"strings"
	"sync"

	"github.com/hxchjm/config"
	"github.com/hxchjm/log"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"time"
)

var (
	_db     *gorm.DB
	_redis  *redis.Client
	_dbName string
	_once   sync.Once
)

type DbCfg struct {
	Addr     string
	User     string
	Password string
	Port     int
	Name     string
}

type RdCfg struct {
	Addr     string
	Password string
	Port     int
}

type gormLogger struct {
}

func (l gormLogger) Printf(s string, v ...interface{}) {
	s = strings.ReplaceAll(s, "\n", " ")
	log.Error(fmt.Sprintf(s, v...))
}

func Init() error {
	if err := InitDB(); err != nil {
		return err
	}
	if err := InitRedis(); err != nil {
		return err
	}
	return nil
}

func InitDB() error {
	var dc DbCfg
	if err := config.Get("DB", &dc); err != nil {
		return err
	}
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&writeTimeout=100s&readTimeout=100s&parseTime=True",
		dc.User, dc.Password, dc.Addr, dc.Port, dc.Name)
	//dsn := "root:root@tcp(127.0.0.1:3306)/go_db?charset=utf8mb4&parseTime=True"
	// open函数只是验证格式是否正确，并不是创建数据库连接
	__db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
		Logger: logger.New(gormLogger{}, logger.Config{
			LogLevel: logger.Warn,
		}),
		//DryRun: true,//控制是否真正写入db
	})
	if err != nil {
		log.Errorf("sql open dsn(%+v) err (%+v)", dsn, err)
		return err
	}

	sqlDB, _ := __db.DB()
	if err = sqlDB.Ping(); err != nil {
		panic(err)
	}
	sqlDB.SetConnMaxLifetime(time.Minute * 20)
	sqlDB.SetConnMaxIdleTime(time.Minute * 20)
	sqlDB.SetMaxIdleConns(10)
	sqlDB.SetMaxOpenConns(10)
	// 与数据库建立连接
	_db = __db
	_dbName = dc.Name
	return nil
}

func InitRedis() error {
	rc := RdCfg{}
	if err := config.Get("RD", &rc); err != nil {
		return err
	}
	_redis = redis.NewClient(&redis.Options{
		Addr:         rc.Addr,
		DialTimeout:  time.Second * 2,
		MaxRetries:   3,
		ReadTimeout:  time.Second * 3,
		WriteTimeout: time.Second * 3,
	})
	return nil
}

func GetRedis() *redis.Client {
	if _redis == nil {
		_once.Do(func() {
			_ = InitRedis()
		})
	}
	return _redis
}

func GetDB() *gorm.DB {
	if _db == nil {
		_once.Do(func() {
			_ = Init()
		})
	}
	return _db
}

func GetDBName() string {
	if _dbName == "" {
		log.Infof("db name is empty")
		panic("db name is empty")
	}
	return _dbName
}
